/* io_usb_samba.c -- remote debug api using Atmel SAM-BA transport
**
** Copyright 2006, Brian Swetland.  All rights reserved.
** See provided LICENSE file or http://frotz.net/LICENSE for details.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

#include "debugger.h"
#include "usb.h"

static void
atmel_sync()
{
    unsigned char buf[2];
    
    if(usb_write("N#",2) != 2) {
        IOERROR("sync failure");
        return;
    }
    if(usb_read(buf,2) != 2) {
        IOERROR("sync failure");
    }
}

static unsigned
atmel_read(unsigned addr, char cmd, int width)
{
    char buf[32];
    int n;
    sprintf(buf,"%c%X,#",cmd,addr);
    n = strlen(buf);
    if(usb_write(buf, n) != n) {
        IOERROR("cannot send command");
        return 0;
    }
    n = 0;
    if(usb_read(&n, width) != width) {
        IOERROR("cannot read reply");
        return 0;
    }
    return n;
}

static void
atmel_write(unsigned addr, unsigned val, char cmd)
{
    char buf[32];
    int n;
    sprintf(buf,"%c%X,%X#",cmd,addr,val);
    n = strlen(buf);
    if(usb_write(buf, n) != n) {
        IOERROR("cannot write command");
    }
}

static void
samba_jump_to(DebugIO *io, unsigned addr)
{
    char buf[32];
    int n;
    sprintf(buf,"G%0X#",addr);
    n = strlen(buf);
    if(usb_write(buf, n) != n) {
        IOERROR("cannot write command");
    }
}

static unsigned
samba_rd32(DebugIO *io, unsigned addr)
{
    return atmel_read(addr, 'w', 4);
}

static void
samba_wr32(DebugIO *io, unsigned addr, unsigned val)
{
    atmel_write(addr, val, 'W');
}

#if 0
//unsigned read16(unsigned addr) { return atmel_read(addr, 'h', 2); }
static unsigned _read8(unsigned addr)  { return atmel_read(addr, 'o', 1); }

//void write16(unsigned addr, unsigned val) { atmel_write(addr, val, 'H'); }
static void _write8(unsigned addr, unsigned val)  { atmel_write(addr, val, 'O'); }

static void
_write_bytes(unsigned addr, void *_ptr, unsigned count)
{
    unsigned char *ptr = (unsigned char *) _ptr;
    while(count-- > 0) {
        write8(addr++, *ptr++);
    }
}

static void
_read_bytes(unsigned addr, void *_ptr, unsigned count)
{
    unsigned char *ptr = (unsigned char*) _ptr;
    while(count-- > 0) {
        *ptr++ = read8(addr++);
    }
}
#endif

static void
samba_connect(DebugIO *io)
{
    if(io->online) return;

    if(usb_open(0x03eb, 0x6124, 1, 0x82, 0x01)) {
        return;
    }

    atmel_sync();
    if(io->error){
        usb_close();
    } else {
        io->online = 1;
    }
}

static void
samba_disconnect(DebugIO *io)
{
    if(io->online) {
        usb_close();
        io->online = 0;
    }   
}

static void
samba_halt(DebugIO *io)
{
}


DebugIO DebugIO_USB_SAMBA =
{
    ._rd32 = samba_rd32,
    ._wr32 = samba_wr32,
    ._rd32x = default_rd32x,
    ._wr32x = default_wr32x,
    ._jump_to = samba_jump_to,
    ._halt = samba_halt,
    .connect = samba_connect,
    .disconnect = samba_disconnect,

    .name = "SAM-BA",
};
